package com.app.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.app.common.SystemConstant;
import com.app.common.TotalConfig;
import com.app.enums.StatusCodeEnum;
import com.app.mapper.CompanyMapper;
import com.app.mapper.GasDetailsMapper;
import com.app.pojo.Company;
import com.app.pojo.GasDetails;
import com.app.service.Impl.GasDetailsServiceImpl;
import com.app.util.COSClientUtil;
import com.app.util.LiExcelHelperUtils;
import com.app.util.Result;
import com.app.util.TokenUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qcloud.cos.COSClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@Controller
@RestController
@RequestMapping("/api")
@Api(tags = "图片上传删除接口")
public class UploadController {
//    @Autowired
//    UserService userService;



    @Autowired
    private GasDetailsMapper gasDetailsMapper;

    @Autowired
    private GasDetailsServiceImpl gasDetailsServiceImpl;


    @Autowired
    private CompanyMapper companyMapper;

    /**
     * 上传文件
     */
    @ApiOperation("上传图片")
    @PostMapping("/upload")
    public Result<?> upload(HttpServletRequest request,
                            @RequestParam("file") MultipartFile file) throws IOException {
        String token = request.getHeader("token");
        if (token == null) {
            return Result.error(StatusCodeEnum.STATUS401.getMsg());
        }
        String mobile = TokenUtils.nothingness(token);

        String type = file.getOriginalFilename();
        if (!type.endsWith("jpg") && !type.endsWith("png") && !type.endsWith("jpeg") && !type.endsWith("gif") && !type.endsWith("bmp")) {
            return Result.error("文件类型错误，请上传图片!");
        }

        File filePath;
        if (!file.isEmpty()) {
            //上传文件路径
            String path = "";
            path = SystemConstant.DEFAULT_UPLOAD_URL;
            //获得上传文件名
            String fileName = file.getOriginalFilename();
            assert fileName != null;
            int lastIndexOf = fileName.lastIndexOf(".");
            String date = getRandomString2(8);
            //获取文件的后缀名 .jpg
            String suffix = fileName.substring(lastIndexOf);
            filePath = new File(path + date + suffix);
            System.out.println(filePath);
            //如果文件目录不存在，创建目录
            if (!filePath.getParentFile().exists()) {
                filePath.getParentFile().mkdirs();
            }
            //将上传文件保存到一个目标文件中
            file.transferTo(filePath);
            return Result.success("/file/" + date + suffix);
        } else {
            return Result.error("上传失败");
        }
    }


    @ApiOperation(value = "下载导入模板文件")
    @GetMapping("/downloadImportTemplateFile")
    public void downloadImportTemplateFile(HttpServletResponse response, String fileName) throws Exception {
        // 定义文件路径
        String filePath = System.getProperty("user.dir") + "/template/燃气表信息收集录入需求表.xlsx";

        File file = FileUtils.getFile(filePath);
        String newfilename = URLEncoder.encode("燃气表信息收集录入需求表", "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename="
                + newfilename + ".xlsx");
        byte[] buffer = new byte[1024];
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = FileUtils.openInputStream(file);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != bis) bis.close();
            if (null != fis) fis.close();
        }
    }


    @ApiOperation(value = "导入模板文件")
    @PostMapping("/importTemplateFile")
    public Result importTemplateFile(HttpServletRequest request,
                                     @RequestParam("file") MultipartFile mfile) throws Exception {
        if (!StpUtil.hasPermission("admin:equipment:import")) {
            return Result.error(TotalConfig.NO_PERMISSION);
        }
        String token = request.getHeader("token");
        if (token == null) {
            return Result.error(StatusCodeEnum.STATUS401.getMsg());
        }

        String type = mfile.getOriginalFilename();
        if (!type.endsWith("xlsx")) {
            return Result.error("文件类型错误，请上传xlsx格式!");
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<String[]> list = LiExcelHelperUtils.readExcelToStringArray(mfile, 0);


        List<String> accountList = new ArrayList<>();
        List<String> gasNumberList = new ArrayList<>();
        QueryWrapper<GasDetails> queryWrapper1 = new QueryWrapper<>();
        List<GasDetails> gas = gasDetailsMapper.selectList(queryWrapper1);
        for (GasDetails gasDetails : gas) {
            accountList.add(gasDetails.getAccount());
            gasNumberList.add(gasDetails.getGasNumber());
        }

        QueryWrapper<Company> queryWrapper2 = new QueryWrapper<>();
        List<Company> companies = companyMapper.selectList(queryWrapper2);
        String companyName = "";
        Integer companyId = null;
        BigDecimal companyUnitPrice = new BigDecimal(0);
        if (companies.size() >= 1) {
            companyName = companies.get(0).getCompanyName();
            companyId = companies.get(0).getId();
            companyUnitPrice = companies.get(0).getUnitPrice();
        }

        //去重
        accountList = new ArrayList<>(new HashSet<>(accountList));
        gasNumberList = new ArrayList<>(new HashSet<>(gasNumberList));

        int validRows = 0; // 用于跟踪有效数据行的数量
        List<GasDetails> addGasDetailslist = new ArrayList<>();
        Set<String> accountSet = new HashSet<>();
        Set<String> gasNumberSet = new HashSet<>();
        List<String> errorList = new ArrayList<>();
        for (int i = 1; i < list.size(); i++) {
            String[] str = list.get(i);
            if (str.length < 8) {
                return Result.error("请下载导入模板编辑后再上传!");
            }
            String account = (str[0] + "").replace(" ", "");
            String user_name = (str[1] + "").replace(" ", "");
            String user_phone = (str[2] + "").replace(" ", "");
            String address = (str[3] + "").replace(" ", "");
            String gas_number = (str[4] + "").replace(" ", "");
            String install_time = (str[5] + "").replace(" ", "");
            String gas_quantity = (str[6] + "").replace(" ", "");
            String notes = (str[7] + "").replace(" ", "");

            System.err.println("account:" + account + " user_name:" + user_name + " user_phone:" + user_phone + " address:" + address + " gas_number:" + gas_number + " install_time:" + install_time + " gas_quantity:" + gas_quantity + " notes:" + notes);

            if (1 == i) {
                if (!"户号".equals(account) || !"客户姓名".equals(user_name) || !"联系电话①".equals(user_phone) || !"详细地址".equals(address)
                        || !"燃气表编号②".equals(gas_number) || !"安装日期".equals(install_time) || !"表具初始读数③".equals(gas_quantity) || !"备注".equals(notes)) {
                    return Result.error("请下载导入模板编辑后再上传!");
                }
            } else {
                if (account.contains("备注")) {
                    break;
                }
                //所有数据为空，则无数据，跳出当前循环
                if (StrUtil.isBlankIfStr(account)
                        && StrUtil.isBlankIfStr(user_name)
                        && StrUtil.isBlankIfStr(user_phone)
                        && StrUtil.isBlankIfStr(address)
                        && StrUtil.isBlankIfStr(gas_number)
                        && StrUtil.isBlankIfStr(install_time)
                        && StrUtil.isBlankIfStr(gas_quantity)
                        && StrUtil.isBlankIfStr(notes)) {
                    break;
                }

                // 如果当前行不是全部为空，则视为有效数据行
                boolean isAllEmpty = StrUtil.isBlankIfStr(account)
                        && StrUtil.isBlankIfStr(user_name)
                        && StrUtil.isBlankIfStr(user_phone)
                        && StrUtil.isBlankIfStr(address)
                        && StrUtil.isBlankIfStr(gas_number)
                        && StrUtil.isBlankIfStr(install_time)
                        && StrUtil.isBlankIfStr(gas_quantity)
                        && StrUtil.isBlankIfStr(notes);

                if (!isValidPhoneNumber(user_phone)) {
                    errorList.add("户号 " + account + "联系电话格式不正确，请重新填写!");
                }

                BigDecimal gas_quantity_bigdecimal = null;
                try {
                    gas_quantity_bigdecimal = new BigDecimal(gas_quantity);
                } catch (Exception e) {
                    e.printStackTrace();
                    errorList.add("户号 " + account + "表具初始读数格式不正确，请重新填写!");
                }

                if (gas_number.length() != 16) {
                    errorList.add("户号 " + account + "燃气表编号格式不正确，请录入16位!");
                }
                LocalDateTime localDateTime = null;
                try {
                    Date date = sdf.parse(install_time);
                    // 使用Instant类作为桥梁
                    Instant instant = date.toInstant();
                    // 转换Instant到LocalDateTime需要指定时区
                    // 这里使用系统默认时区作为示例
                    localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
                } catch (Exception e) {
                    e.printStackTrace();
                    errorList.add("户号 " + account + " 日期格式不正确，请重新填写！");
                }
                if (accountList.contains(account)) {
                    errorList.add("户号 " + account + " 已存在！");
                }
                if (gasNumberList.contains(gas_number)) {
                    errorList.add("燃气表编号 " + account + " 已存在！");
                }
                // 校验表格中账号是否重复
                if (!accountSet.add(account)) {
                    errorList.add("户号 " + account + " 重复！");
                }
                // 校验表格中燃气表编号是否重复
                if (!gasNumberSet.add(gas_number)) {
                    errorList.add("燃气表编号 " + gas_number + " 重复！");
                }

                if (!isAllEmpty) {
                    validRows++; // 增加有效数据行的计数器
                    GasDetails gasDetails = new GasDetails();
                    gasDetails.setAccount(account);
                    gasDetails.setUserName(user_name);
                    gasDetails.setUserAddress(address);
                    gasDetails.setUserPhone(user_phone);
                    gasDetails.setBalance(new BigDecimal(0));
                    gasDetails.setGasNumber(gas_number);
                    gasDetails.setGasMeterBalance(gas_quantity_bigdecimal);
                    gasDetails.setGasMeterTotal(gas_quantity_bigdecimal);
                    gasDetails.setCompanyName(companyName);
                    gasDetails.setCompanyId(companyId);
                    gasDetails.setUnitPrice(companyUnitPrice);
                    gasDetails.setInstallTime(localDateTime);
                    gasDetails.setNotes(notes);
                    gasDetails.setCreateTime(localDateTime);
                    gasDetails.setStatus(1);
                    gasDetails.setValveStatus(0);
                    gasDetails.setAccountOpeningStatus(0);
                    addGasDetailslist.add(gasDetails);
                } else {
                    return Result.error("表格中所有列均必填，请填写完整后导入!");
                }
            }
        }
        //如果有错误数据，则返回错误信息
        if (errorList.size() > 0) {
            //去重
            errorList = new ArrayList<>(new HashSet<>(errorList));
            String result = String.join(";", errorList);
            return Result.error(result);
        }

        if (validRows != addGasDetailslist.size()) {
            return Result.error("表格中有错误数据，请填写后重新上传!");
        }
        //批量插入数据
        gasDetailsServiceImpl.batchInsert(addGasDetailslist);
        return Result.success("导入成功!");
    }


    // 手机号正则表达式
    public boolean isValidPhoneNumber(String phoneNumber) {
        String regex = "^(13|14|15|17|18)[0-9]{9}$";
        return phoneNumber != null && phoneNumber.matches(regex);
    }

    public boolean isValidAmount(String amount) {
        // 金额的正则表达式，允许整数部分和小数部分（小数点后最多两位）
        // 注意：这个正则表达式假设金额字符串中不包含货币符号，且金额不会以小数点开头
        String regex = "^\\d+(\\.\\d{1,2})?$";

        return amount != null && amount.matches(regex);
    }


    //删除对象
    @ApiOperation(value = "删除图片")
    @GetMapping("/deleteObject")
    public Result<Object> deleteObject(String filename) {
        //获取COSClient对象
        COSClient cosClient = COSClientUtil.getCosClient();
        // Bucket 的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
        String bucketName = SystemConstant.bucketName;
        // 指定被删除的文件在 COS 上的路径，即对象键。例如对象键为 folder/picture.jpg，则表示删除位于 folder 路径下的文件 picture.jpg
        String key = "/uploads/FFuFQ6QV.png";
        cosClient.deleteObject(bucketName, key);
        return Result.success("删除成功");
    }


    //可以指定字符串的某个位置是什么范围的值
    public static String getRandomString2(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(3);
            long result = 0;
            switch (number) {
                case 0:
                    result = Math.round(Math.random() * 25 + 65);
                    sb.append(String.valueOf((char) result));
                    break;
                case 1:
                    result = Math.round(Math.random() * 25 + 97);
                    sb.append(String.valueOf((char) result));
                    break;
                case 2:
                    sb.append(String.valueOf(new Random().nextInt(10)));
                    break;
            }
        }
        return sb.toString();
    }
}
